package main

import (
	"fmt"
	"io"
	"os"
	"syscall"
	"unsafe"
)

type branchPageElement struct {
	pos   uint32
	ksize uint32
	pgid  int
	ptr  uintptr
}
type leafPageElement struct {
	pos   uint32
	ksize uint32
	vsize uint32
}
type page struct {
	id       int
	ptr      uintptr
}
func (p *page) leafPageElement(index uint16) *leafPageElement {
	n := &((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[index]
	return n
}
var fd  *os.File
var err error
func init()  {
	fd, err  = os.OpenFile("./bolt.db",os.O_RDWR|os.O_CREATE,0644)
	if err != nil {
		panic(err)
	}
}

type keyValue struct {
	key string
	value string
}
type pgid int64
type page2 struct {
	id       pgid
	flags    uint16 //页类型，区分页保存的具体的数据类型
	count    uint16 //元素个数
	overflow uint32 //对应节点溢出页的个数，即使用 overflow+1 个页来保存对应节点
	ptr      uintptr //指向具体的数据
}
type Student struct {
	Id int
	Age int
}
func SimpleExample(){
	pid := pgid(1)
	pageSize := os.Getpagesize()
	buf := make([]byte,pageSize)
	p2 := (*page2)(unsafe.Pointer(&buf[0])) //将字节数组转换为page
	p2.id = pid
	p2.flags = 1
	p2.overflow = 0

	f, err  := os.OpenFile("./test.db",os.O_RDWR|os.O_CREATE,0644)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer f.Close()
	//写
	stds := make([]Student,0)
	stds = append(stds,Student{1,12})
	stds = append(stds,Student{2,13})
	stds = append(stds,Student{3,14})
	for i,val := range stds { //写
		//将ptr 转换为 student 数组
		std := &((*[0x7FFFFFF]Student)(unsafe.Pointer(&p2.ptr)))[i]
		std.Id =val.Id
		std.Age = val.Age
		p2.count++
	}
	off := int(pid-1)*pageSize
	f.WriteAt(buf[:pageSize],int64(off))

	//读
	rbuf := make([]byte,pageSize)
	f.ReadAt(rbuf,int64(off))
	p3 := (*page2)(unsafe.Pointer(&rbuf[0])) //将字节数组转换为page
	//fmt.Println(p3.id,p3.flags,p3.overflow,p3.count)
	var i uint16
	for i = 0; i<p3.count;i++ {
		//将ptr 转换为 student 数组
		readStd := ((*[0x7FFFFFF]Student)(unsafe.Pointer(&p2.ptr)))[i]
		fmt.Println(readStd)
	}
}
func main() {
	SimpleExample()
	return

	defer fd.Close()
	//p := &page{
	//	id: 1,
	//}
	//pageSize := os.Getpagesize()
	pp := read(1)
	for i := 0; i<3; i++ {
		write(i)
	}

	for i:=0;i<3;i++ {
		n := pp.leafPageElement(uint16(i))
		fmt.Println(n)
		buf := (*[0xffffffff]byte)(unsafe.Pointer(n))
		// 从第二个元素取，切取的长度为2，容量也为2
		//new_slice := my_slice[1:3:3]
		key := (*[0xffffffff]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize:n.ksize]
		val := (*[0xffffffff]byte)(unsafe.Pointer(&buf[n.pos+n.ksize]))[:n.vsize:n.vsize]
		kv := keyValue{
			key:   string(key),
			value: string(val),
		}
		fmt.Println(kv)
	}
	//hmap, err := syscall.CreateFileMapping(syscall.Handle(fd.Fd()) , nil, syscall.PAGE_READONLY, 0, 0, nil)
	//defer syscall.CloseHandle(hmap)
}

func read(id int) *page {
	num,_ := fd.Seek(0,io.SeekEnd)
	fmt.Println("NUM-------",num)
	hmap, err := syscall.CreateFileMapping(syscall.Handle(fd.Fd()) , nil, syscall.PAGE_READWRITE, 0, 0, nil)
	if err != nil {
		fmt.Println(err)
		return nil
	}
	defer syscall.CloseHandle(hmap)
	addr, err := syscall.MapViewOfFile(hmap, syscall.FILE_MAP_READ, 0, 0, 0)
	data := (*[0xffffffff]byte)(unsafe.Pointer(addr))
	//pages := (*[0xffffffff]page)(unsafe.Pointer(&data[0]))
	//pp := &pages[id]
	pageSize := os.Getpagesize()
	pos := id*pageSize
	pp := (*page)(unsafe.Pointer(&data[pos]))
	fmt.Println(pp.id)

	return  pp

}

func write(id int)  {
	pageSize := os.Getpagesize()
	buf := make([]byte,pageSize)
	p := (*page)(unsafe.Pointer(&buf[0]))
	p.id = id

	eles := make([]keyValue,0)
	str := fmt.Sprintf("ab-%d",id)
	eles = append(eles,keyValue{key: str,value: "ab1c"})
	eles = append(eles,keyValue{key: "abcd",value: "abcc1def"})
	eles = append(eles,keyValue{key: "abf",value: "abcc1c"})
	lsize := int(unsafe.Sizeof(leafPageElement{}))
	b := (*[0x7FFFFFF]byte)(unsafe.Pointer(&p.ptr))[lsize*len(eles):]
	for i,val := range eles {
		elem := p.leafPageElement(uint16(i))
		elem.vsize = uint32(len(val.value))
		elem.ksize = uint32(len(val.key))

		elem.pos = uint32(uintptr(unsafe.Pointer(&b[0])) - uintptr(unsafe.Pointer(elem)))
		copy(b[0:],val.key)
		b = b[len(val.key):]
		copy(b[0:],val.value)
		b = b[len(val.value):]
	}
	off := p.id*pageSize
	fmt.Println(fd.WriteAt(buf[:pageSize],int64(off)))
	fmt.Println(p.id)

}
